import myTools.ThreadPoolTools;
import org.junit.jupiter.api.Test;

import java.util.Arrays;
import java.util.List;
import java.util.Random;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 为方便测试,用@Test来执行代码
 *
 * @author yhy
 * @version 1.0.0
 * @create 2024/11/2 18:13
 */
public class ThreadPoolTest {
    /**
     * 1个最简单的异步编排案例
     */
    @Test
    public void OneCompletableFutureCase() throws ExecutionException, InterruptedException {
        CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "我是异步线程, 返回了一个苹果");
        // 调用get获取结果
        System.out.println(future.get());
    }

    /**
     * 单个CompletableFuture,适用于除了主线程之外只需要一个次线程调用的情况
     * runAsync: 运行一个异步任务,不能返回结果
     */
    @Test
    public void testOneCompletableFuture_runAsync() {
        // 场景: 给收件人发送电子邮件
        List<String> persons = Arrays.asList("张三", "李四", "王五", "赵六");
        // main task do someThing...
        CompletableFuture.runAsync(() -> {
            for (String person : persons) {
                System.out.println("发送邮件给" + person);
            }
        });
    }

    /**
     * 单个CompletableFuture,适用于除了主线程之外只需要一个次线程调用的情况
     * supplyAsync: 运行一个异步任务并且返回结果
     */
    @Test
    public void testOneCompletableFuture_supplyAsync() throws ExecutionException, InterruptedException {
        // 场景: 获取用户基本信息,并获取用户名下的所有订单号
        // main task do get user info
        CompletableFuture<StringBuffer> future = CompletableFuture.supplyAsync(() -> {
            StringBuffer sb = new StringBuffer();
            String pre = "ORDER-";
            for (int i = 0; i < 10; i++) {
                sb.append(pre).append(new Random().nextInt(1000)).append(",");
            }
            return sb;
        });
        StringBuffer orders = future.get();
        System.out.printf("订单号:%s\n", orders);

        // 如果需要订单做处理, 可以用thenApply()
        CompletableFuture<String> handleFuture = future
                .thenApply(orderStr -> orderStr.toString().replace(",", "M,"));
        String handleOrders = handleFuture.get();
        System.out.printf("处理后的订单号:%s\n", handleOrders);
    }

    /**
     * 多个CompletableFuture,适用于多任务执行
     * allOf: 所以CompletableFuture执行完成后,返回新的1个CompletableFuture
     */
    @Test
    public void testMultiCompletableFuture_allOf() throws ExecutionException, InterruptedException {
        // 场景: 模拟不同耗时的三种任务,全部返回则主线程结束
        CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
            try {
                System.out.println("执行1");
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                throw new IllegalStateException(e);
            }
            return "Future1-香蕉";
        }, ThreadPoolTools.getThreadPoolExecutor());

        CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
            try {
                System.out.println("执行2");
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                throw new IllegalStateException(e);
            }
            return "Future2-水蜜桃";
        }, ThreadPoolTools.getThreadPoolExecutor());

        CompletableFuture<String> future3 = CompletableFuture.supplyAsync(() -> {
            try {
                System.out.println("执行3");
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                throw new IllegalStateException(e);
            }
            return "Future3-咸豆腐脑";
        }, ThreadPoolTools.getThreadPoolExecutor());
        List<CompletableFuture<String>> futures = Arrays.asList(future1, future2, future3);

        CompletableFuture<Void> allOf = CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]));
        CompletableFuture<List<String>> listCompletableFuture = allOf
                .thenApply(item -> futures.stream().map(CompletableFuture::join).collect(Collectors.toList()));

        System.out.println("最终返回:" + listCompletableFuture.get());
    }

    /**
     * 多个CompletableFuture,适用于多任务执行
     * anyOf: 任意的CompletableFuture执行完成后,返回新的1个CompletableFuture
     */
    @Test
    public void testMultiCompletableFuture_anyOf() throws ExecutionException, InterruptedException {
        // 场景: 模拟不同耗时的三种任务,任意一个返回则主线程结束
        CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
            try {
                System.out.println("执行1");
                TimeUnit.SECONDS.sleep(new Random().nextInt(10));
            } catch (InterruptedException e) {
                throw new IllegalStateException(e);
            }
            return "Future1-苹果";
        });

        CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
            try {
                System.out.println("执行2");
                TimeUnit.SECONDS.sleep(new Random().nextInt(10));
            } catch (InterruptedException e) {
                throw new IllegalStateException(e);
            }
            return "Future2-橘子";
        });

        CompletableFuture<String> future3 = CompletableFuture.supplyAsync(() -> {
            try {
                System.out.println("执行3");
                TimeUnit.SECONDS.sleep(new Random().nextInt(10));
            } catch (InterruptedException e) {
                throw new IllegalStateException(e);
            }
            return "Future3-菠萝";
        });

        CompletableFuture<Object> anyOfFuture = CompletableFuture.anyOf(future1, future2, future3);

        System.out.println("最终返回:" + anyOfFuture.get());
    }

    /**
     * 发生异常时,api对异常的处理方式一: exceptionally
     * exceptionally,当异常发生时,内部逻辑才会被调用,接受一个Function函数,继续返回CompletableFuture类
     * 值得注意的是:exceptionally只对它前面第一个异常兜底,
     *  如果把这一步当成C,前面有A,B且都发生了异常,那么B中的逻辑将不会执行
     */
    @Test
    public void testCompletableFutureException_exceptionally() throws ExecutionException, InterruptedException {
        int num1 = 6;
        int num2 = 0;
        // 异步方式执行两个数相除
        CompletableFuture<Integer> future = CompletableFuture
                .supplyAsync(() -> {
                    System.out.println("步骤1执行...");
                    return num1 / num2;
                })
                .exceptionally(e -> {
                    System.out.println("Exception1-->" + e);
                    return 0;
                })
                .thenApply(i -> {
                    System.out.println("步骤2执行...");
                    return i / 0;
                })
                .exceptionally(e -> {
                    System.out.println("Exception2-->" + e);
                    return 0;
                });
        System.out.printf("%s和%s的计算结果:[%s]", num1, num2, future.get());
    }

    /**
     * 发生异常时,api对异常的处理方式二: handle
     * handle,无论异常是否发生,此中的逻辑都会执行,接受一个BiFunction函数,继续返回CompletableFuture类
     */
    @Test
    public void testCompletableFutureException_handle() throws ExecutionException, InterruptedException {
        int num1 = 6;
        int num2 = 0;
        CompletableFuture<Integer> future = CompletableFuture
                .supplyAsync(() -> {
                    System.out.println("步骤1执行...");
                    return num1 / num2;
                })
                .handle((res,ex) -> {
                    if (ex != null) {
                        System.out.println("Exception1-->" + ex);
                        return 0;
                    }
                    // 无异常,正常返回原res即可
                    return res;
                });
        System.out.println("计算结果:" + future.get());
    }

}
